home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-04-24 | 12.5 KB | 400 lines | [TEXT/MPS ] |
- UNIT DragManager;
- {Version 1.0 Saturday, April 18, 1987 by Scott T. Boyd of
- the MacHax™ Group. Many thanks to Greg Marriott, also a
- member of the MacHax Group. © 1987 by The MacHax Group,
- Bryan, TX.}
- {$D+} {put in debug names}
- {$R+} {range checking on}
- {$OV+} {overflow checking on}
- {$N+} {pass routine names to linker, so they're not anonymous}
- INTERFACE
- USES {$LOAD pinterfaces.dump}
- MemTypes,QuickDraw,OsIntf,PasLibIntf,ToolIntf,
- PackIntf,IntEnv,CursorCtl;
-
- type
- shadowRecord = record
- visible : boolean;
- dx, dy : integer;
- thePattern : Pattern;
- copyMode : integer;
- end;
- dragHandle = ^dragPtr;
- dragPtr = ^dragRecord;
- dragRecord = record
- shadowBits, {the shadow}
- underShadowBits, {what's under the shadow}
- underBits, {bits obscured by picture}
- pictureBits : BitMap; {the picture}
- shadowRegion,
- thePictureRgn : RgnHandle; {use this for masking}
- end;
- bitMapPtr = ^BitMap;
- var
- shadowStuff : shadowRecord;
-
- function InitDrag ( userOffscreenBits : bitMapPtr ) : boolean;
- function NewDraggable ( thePicture : PicHandle;
- userPicBits, userShadowBits : bitMapPtr;
- var dragStuff : DragHandle ) : boolean;
- procedure DragItTo ( dragStuff: DragHandle; mousePt: point;
- centered : boolean );
- procedure DisposeDraggable ( dragStuff : DragHandle );
- procedure UpdateOffScreen ( dragStuff : DragHandle;
- Procedure drawProc );
- procedure CloseDrag ( disposeBitMap : boolean );
-
- IMPLEMENTATION
- const
- shadow_x = 4;
- shadow_y = 6;
- var
- offScreenBits : BitMap; {the picture}
-
- wMgrPort,
- oldPort,
- offPort : GrafPtr;
-
- updateRegion : RgnHandle;
-
- lastRect, {this + dragRect => updateRegion}
- otherUpdateRect, {updateRect clipped to include only bits onscreen}
- updateRect, {union of dragRect and lastRect}
- dragRect, {size of the picture & centered over cursor}
- tempBounds : Rect; {used in creating bitmaps}
-
- mousePt, {used to position dragRect}
- otherMousePt, {used to see if cursor has moved}
- testPt : Point; {used to see if cursor has moved}
-
- synchCount : longint; {wait for TickCount to change before drawing}
-
- procedure Debugger; INLINE $A9FF;
-
- function NewBitMap( var theBitMap : BitMap; theRect : Rect ): ptr;
- begin
- with theBitMap, theRect do
- begin
- rowBytes := ((right-left+15) DIV 16) * 2;
- baseAddr := NewPtr(rowBytes * (bottom-top));
- bounds := theRect;
- if MemError <> noErr then NewBitMap := nil
- else NewBitMap := baseAddr;
- end;
- end; {NewBitMap}
-
- function InitDrag ( userOffscreenBits : bitMapPtr ) : boolean;
- begin
- InitDrag := false;
- {do all the work in the wMgrPort}
- GetPort( oldPort );
- GetWMgrPort( wMgrPort );
- {now make an offscreen bitmap to hold the whole screen}
- {if one already exists, ignore what they pass in}
- if userOffScreenBits <> nil
- then offScreenBits := BitMap(userOffScreenBits^)
- else if NewBitMap( offScreenBits, screenBits.bounds ) = nil
- then exit( InitDrag );
-
- {make the grafport to play with. this way I can really trash up
- the grafport and not worry about saving and restoring the old one}
- offPort := GrafPtr( NewPtr( sizeof( GrafPort ) ) );
- if offPort = nil then
- begin
- DisposPtr( offScreenBits.baseAddr );
- exit( InitDrag );
- end;
- {set up off screen port so we can draw in it}
- OpenPort( offPort );
- RectRgn( thePort^.visRgn, thePort^.clipRgn^^.rgnBBox );
-
- {create the region to update with}
- updateRegion := NewRgn;
- if updateRegion = nil then
- begin
- DisposPtr( offScreenBits.baseAddr );
- ClosePort( offPort );
- DisposPtr( Pointer( offPort ));
- SetPort( oldPort );
- exit( InitDrag );
- end;
-
- {set up the default shadow stuff}
- with shadowStuff do
- begin
- visible := true;
- dx := shadow_x;
- dy := shadow_y;
- thePattern := black;
- copyMode := SrcXor;
- end;
- {copy the screen}
- CopyBits( screenBits, offScreenBits, screenBits.bounds,
- offScreenBits.bounds, srcCopy, nil );
- InitDrag := true;
-
- SetPort( oldPort );
- end;{InitDrag}
-
- function NewDraggable ( thePicture : PicHandle;
- userPicBits, userShadowBits: bitMapPtr;
- var dragStuff : DragHandle ) : boolean;
- procedure TestNil ( theThing : ptr );
- begin
- if theThing = nil then
- begin
- DisposeDraggable ( dragStuff );
- NewDraggable := false;
- SetPort( oldPort );
- exit ( NewDraggable );
- end;
- end; {TestNil}
- begin
- GetPort( oldPort );
- SetPort( offPort );
- dragStuff := DragHandle( NewHandle( sizeOf( dragRecord )));
- if dragStuff = nil then
- begin
- NewDraggable := false;
- SetPort( oldPort );
- exit( NewDraggable );
- end;
-
- MoveHHi( Handle( dragStuff ));
- HLock( Handle( dragStuff ) );
- with dragStuff^^ do begin
- {try to allocate and erase the following bitmaps
- - pictureBits holds the bitmap to display
- - shadowBits holds the shadow
- - underBits holds the bits obscured by the picture
- - underShadowBits holds the bits obscured by the shadow
- - offScreenBits holds the entire screen's image
- }
- {create a bitmap for the picture the size of the picture frame}
- tempBounds := thePicture^^.picFrame;
- if userPicBits <> nil
- then pictureBits := BitMap(userPicBits^)
- else TestNil ( NewBitMap( pictureBits, tempBounds ) );
- {now create the drop shadow bitmap}
- if userShadowBits <> nil
- then shadowBits := BitMap(userShadowBits^)
- else TestNil ( NewBitMap( shadowBits, tempBounds ) );
- {home tempBounds before setting up underBits}
- with tempBounds do OffSetRect( tempBounds, -left, -top );
- TestNil ( NewBitMap( underBits, tempBounds ) );
- {make the under-the-shadow bitmap the same size as the other underBits}
- TestNil ( NewBitMap( underShadowBits, tempBounds ) );
- {clear out the bitmap for the picture}
- SetPortBits( pictureBits );
- EraseRect( pictureBits.bounds );
-
- {make a region for the drop-shadow}
- shadowRegion := NewRgn;
- TestNil ( pointer( shadowRegion ));
- {draw the picture into pictureBits & create thePictureRgn}
- thePictureRgn := NewRgn;
- TestNil ( pointer( thePictureRgn ));
- OpenRgn;
- HLock( Handle( thePicture ));
- DrawPicture( thePicture, thePicture^^.picFrame );
- HUnlock( Handle( thePicture ));
- CloseRgn( thePictureRgn );
- if EmptyRgn( thePictureRgn )
- then RectRgn( thePictureRgn, thePicture^^.picFrame );
- {put the picture in pictureBits}
- SetPortBits( pictureBits );
- HLock( Handle( thePicture ));
- DrawPicture( thePicture, thePicture^^.picFrame );
- HUnlock( Handle( thePicture ));
-
- {clear out shadowBits}
- SetPortBits( shadowBits );
- EraseRect( shadowBits.bounds );
- {fill in the shadow}
- CopyRgn( thePictureRgn, shadowRegion );
- PenMode( PatCopy );
- PenPat( shadowStuff.thePattern );
- PaintRgn( shadowRegion );
- OffSetRgn( shadowRegion, shadowStuff.dx, shadowStuff.dy );
-
- {the bounding rect surrounding the picture in position}
- dragRect := pictureBits.bounds;
-
- SetRect( lastRect, 0,0,0,0 );
- end; {with dragStuff^^}
- HUnlock( Handle( dragStuff ) );
- NewDraggable := true;
- SetPort( oldPort );
- end; {InitDrag}
-
- procedure DragItTo ( dragStuff: DragHandle; mousePt: point;
- centered : boolean );
- begin
- {we'll do all our work in the window manager port}
- GetPort( oldPort );
- SetPort( offPort );
-
- MoveHHi( Handle( dragStuff ) );
- HLock( Handle( dragStuff ) );
- with dragStuff^^ do begin
- otherMousePt := mousePt;
- {home the region, the rect and the shadow region}
- OffSetRgn( thePictureRgn, -dragRect.left, -dragRect.top );
- OffSetRgn( shadowRegion, -dragRect.left, -dragRect.top );
- OffSetRect( dragRect, -dragRect.left, -dragRect.top );
- {center the object over the cursor}
- {calculate mousePt here because we know the rect is home'd}
- if centered then
- begin
- mousePt.h := mousePt.h - dragRect.right div 2;
- mousePt.v := mousePt.v - dragRect.bottom div 2;
- end;
- OffSetRect( dragRect, mousePt.h, mousePt.v );
- OffSetRgn( thePictureRgn, mousePt.h, mousePt.v );
- OffSetRgn( shadowRegion, mousePt.h, mousePt.v );
-
- {save bits underneath the shadow and then the bits under the picture}
- if shadowStuff.visible
- then begin
- {work with the rectangle around the shadow}
- with shadowStuff do OffsetRect( dragRect, dx, dy );
- {remove any part of dragRect which is off the screen (clip it)}
- if SectRect( screenBits.bounds, dragRect, updateRect ) then {};
- {the destination rectangle will be home'd}
- otherUpdateRect := updateRect;
- with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
- {take the snapshot}
- CopyBits( offScreenBits, underShadowBits, updateRect, otherUpdateRect,
- srcCopy,nil );
- {move dragRect back over the picture area}
- with shadowStuff do OffsetRect( dragRect, -dx, -dy );
- end; {only if visible}
-
- {clip dragRect to inside the screen}
- if SectRect( screenBits.bounds, dragRect, updateRect ) then {};
- {home the destination rect}
- otherUpdateRect := updateRect;
- with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
- {say “cheese”}
- CopyBits( offScreenBits, underBits, updateRect, otherUpdateRect,
- srcCopy,nil );
-
- {draw my object's shadow.
- => modification point <= if the copyMode is srcCopy you should
- use shadowRegion to mask instead of nil.}
- if shadowStuff.visible
- then begin
- with shadowStuff do OffsetRect( dragRect, dx, dy );
- CopyBits( shadowBits, offScreenBits, shadowBits.bounds, dragRect,
- shadowStuff.copyMode, nil );
- with shadowStuff do OffsetRect( dragRect, -dx, -dy );
- end; {only if visible}
-
- {draw my object}
- CopyBits( pictureBits, offScreenBits, pictureBits.bounds, dragRect,
- srcCopy, thePictureRgn );
-
- {update what was on there plus the new position for the object}
- UnionRect( dragRect, lastRect, updateRect );
- {include the shadow's rectangle}
- if shadowStuff.visible
- then begin
- with shadowStuff do OffsetRect( dragRect, dx, dy );
- UnionRect( dragRect, updateRect, updateRect );
- with shadowStuff do OffsetRect( dragRect, -dx, -dy );
- end; {only if visible}
- {clip it all to the screen boundaries}
- if SectRect( screenBits.bounds, updateRect, updateRect ) then {};
- RectRgn( updateRegion, updateRect );
- {wait for just the right moment}
- {i can't see an improvement, can you?}
- { synchCount := TickCount;
- repeat until TickCount <> synchCount;
- } {put it on the screen}
- CopyBits( offScreenBits, screenBits, updateRect, updateRect,
- srcCopy, nil );
- {restore bits underneath the picture}
- {remove any part of dragRect which is off the screen}
- if SectRect( dragRect, screenBits.bounds, updateRect ) then {};
- {use a home'd rectangle for underBits}
- otherUpdateRect := updateRect;
- with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
- CopyBits( underBits, offScreenBits,
- otherUpdateRect, updateRect, srcCopy, nil );
- {remember what parts of screenBits need to be fixed for next time}
- lastRect := dragRect;
- {restore bits underneath the shadow}
- if shadowStuff.visible
- then begin
- with shadowStuff do OffsetRect( dragRect, dx, dy );
- {clip it}
- if SectRect( dragRect, screenBits.bounds, updateRect ) then {};
- {home it}
- otherUpdateRect := updateRect;
- with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
- {shoot it}
- CopyBits( underShadowBits, offScreenBits,
- otherUpdateRect, updateRect, srcCopy, nil );
- {add to parts of screenBits to be fixed for next time}
- UnionRect( lastRect, dragRect, lastRect );
- with shadowStuff do OffsetRect( dragRect, -dx, -dy );
- end;{only if shadow visible}
-
- end; {with dragStuff^^}
- HUnlock( Handle( dragStuff ));
- SetPort( oldPort );
- end; {DragItTo}
-
- procedure DisposeDraggable( dragStuff : DragHandle );
- begin {tidy up}
- if dragStuff <> nil then begin
- HLock( Handle( dragStuff ) );
- with dragStuff^^ do
- begin
- if pictureBits.baseAddr <> nil
- then DisposPtr( pictureBits.baseAddr );
- if underBits.baseAddr <> nil
- then DisposPtr( underBits.baseAddr );
- if underShadowBits.baseAddr <> nil
- then DisposPtr( underShadowBits.baseAddr );
- if shadowBits.baseAddr <> nil
- then DisposPtr( shadowBits.baseAddr );
- if offScreenBits.baseAddr <> nil
- then CopyBits( offScreenBits, screenBits,
- offScreenBits.bounds, screenBits.bounds,
- srcCopy, nil );
- if thePictureRgn <> nil
- then DisposHandle( Handle(thePictureRgn) );
- if shadowRegion <> nil
- then DisposHandle( Handle(shadowRegion) );
- end; {with dragStuff}
- HUnlock ( Handle( dragStuff ) );
- DisposHandle( Handle( dragStuff ) );
- end; {dragStuff <> nil}
- end; {DisposeDraggable}
-
- procedure UpdateOffScreen ( dragStuff : DragHandle;
- Procedure drawProc );
- begin
- GetPort( oldPort );
- SetPort( offPort );
- SetPortBits( offScreenBits );
- drawProc;
- SetPort( oldPort );
- end; {UpdateOffScreen}
-
- procedure CloseDrag ( disposeBitMap : boolean );
- begin
- if offPort <> nil then
- begin
- ClosePort( offPort );
- DisposPtr( Pointer(offPort) );
- end;
- if updateRegion <> nil
- then DisposHandle( Handle(updateRegion) );
- if disposeBitMap then
- if offscreenBits.baseAddr <> nil
- then DisposPtr( offScreenBits.baseAddr );
- end;{CloseDrag}
-
- END. {unit Drag}